07. Numpy-矩阵处理

本章概要

  • 学习材料:收益矩阵、资产权重与协方差矩阵。
  • 本章任务:运行 lst-covariance-matrixlst-portfolio-variance,用矩阵乘法计算组合风险。
  • 完成后你将得到:协方差矩阵、相关矩阵、权重和与组合方差。
  • 自我检查:以双重求和复算 w’Σw;维度错位、权重和不为1或矩阵非有限时先检查原因。
  • 拓展练习:把矩阵风险分析应用到另一权重方案。

核心与扩展路线

  • 本章核心(纳入随堂练习):二维数组、点积、协方差/相关矩阵,以及 \(w'\Sigma w\) 的计算与双重求和核对。
  • 可选扩展(不决定完成本章):线性系统、APT、秩/逆、特征分解、PCA 与伪逆;须先掌握线性代数和最小二乘。
  • 方法选择:方阵满秩可用 solve;非方阵或秩亏时才讨论 lstsq/pinv,但数值解不能修复经济识别问题;PCA 只做探索性降维,不作因果解释。

矩阵在金融中的核心地位

矩阵(Matrix)是金融数学的核心工具,广泛应用于:

  • 投资组合优化:N只资产的收益率表示为N维向量
  • 协方差矩阵:N×N矩阵描述资产间的风险关系
  • 因子模型:收益率 = 因子载荷 × 因子收益 + 特质收益
  • 期权定价与主成分分析:矩阵运算无处不在

理解矩阵运算是掌握现代投资组合理论(MPT)和CAPM的基础。

矩阵的创建方法

Listing 1: 创建NumPy矩阵的不同方法
import numpy as np  # 导入NumPy库

# ==================== 方法1:使用二维数组创建矩阵(推荐) ====================
matrix1 = np.array([
    [1, 2, 3],  # 第一行
    [4, 5, 6],  # 第二行
    [7, 8, 9]   # 第三行
])
print('3×3矩阵:')
print(matrix1)
3×3矩阵:
[[1 2 3]
 [4 5 6]
 [7 8 9]]

创建特殊矩阵

Listing 2: 创建特殊矩阵:单位矩阵、零矩阵、全1矩阵
展开实现代码
import numpy as np

# 单位矩阵:对角线为1,其余为0
identity = np.eye(3)
print('单位矩阵:')
print(identity)

# 零矩阵:2行3列全0
zeros = np.zeros((2, 3))
print('\n零矩阵:')
print(zeros)

# 全1矩阵:2行4列全1
ones = np.ones((2, 4))
print('\n全1矩阵:')
print(ones)
单位矩阵:
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

零矩阵:
[[0. 0. 0.]
 [0. 0. 0.]]

全1矩阵:
[[1. 1. 1. 1.]
 [1. 1. 1. 1.]]

创建对角矩阵

Listing 3: 创建对角矩阵
import numpy as np

# diag函数创建对角矩阵,参数为对角线元素
diag = np.diag([1, 2, 3])
print('对角矩阵:')
print(diag)
对角矩阵:
[[1 0 0]
 [0 2 0]
 [0 0 3]]

在金融中,对角矩阵可用于表示各资产的独立波动率。

矩阵 vs 数组:始终使用 ndarray

特性 np.matrix(已弃用) np.ndarray(推荐)
* 运算符 矩阵乘法 元素乘法
维度 始终2维 可以任意维
状态 已弃用(1.20+) 推荐使用

最佳实践:始终使用 np.ndarray 表示矩阵,使用 @ 运算符进行矩阵乘法。

点积(Dot Product)的数学定义

两个向量 \(\mathbf{a}\)\(\mathbf{b}\) 的点积为:

\[ \large{\mathbf{a} \cdot \mathbf{b} = \sum_{i=1}^{n} a_i b_i = a_1b_1 + a_2b_2 + \cdots + a_nb_n} \]

金融含义:点积用于计算加权平均,如投资组合收益率:

\[ \large{R_p = \sum_{i=1}^{n} w_i R_i = \mathbf{w} \cdot \mathbf{R}} \]

其中 \(\mathbf{w}\) 是权重向量,\(\mathbf{R}\) 是收益率向量。

运行前预测|实战:使用点积计算投资组合日收益率

  • 输入预测:运行前先写出 return_0526weightreturn_daily 的业务含义、数据类型或取值范围,并判断哪一个输入最可能改变结果。
  • 结果预测:不展开答案,先预测将得到“投资组合5月26日收益率为:{return_daily}”相关结果;同时写出方向、数量级或表格/图形结构。
  • 完成要求:能独立说明本任务从输入到“实战:使用点积计算投资组合日收益率”结果的关键步骤,原样录入平台代码并得到可核对的运行结果。

⭐ 实战:使用点积计算投资组合日收益率

# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import numpy as np  # 导入NumPy数值计算库
#使用列表定义5月26日收益率数据 return_0526、权重数据 weight。
return_0526=[0.0172,0.0243,-0.0029,0.0021]
weight=[0.15,0.20,0.25,0.4]  # 定义列表weight
#计算投资组合日收益率
return_daily=np.dot(return_0526,weight).round(3)
print(f'投资组合5月26日收益率为:{return_daily}')  # 输出投资组合5月26日收益率为

任务复盘|实战:使用点积计算投资组合日收益率

运行后核对:核对 return_0526weightreturn_daily 是否按预测参与运算,实际输出是否与预测一致;若不一致,先检查类型、单位、索引/字段和运算顺序。

拓展练习:把对象或期间改为一家长三角上市公司或一组 A 股资产;先预测指标方向,再说明结果能支持和不能支持的决策。

点积的深层含义

  • 几何意义\(\mathbf{a} \cdot \mathbf{b} = \|\mathbf{a}\| \|\mathbf{b}\| \cos\theta\)
  • 投资组合收益\(\sum w_i R_i\)
  • 因子收益\(\sum \beta_i F_i\)
  • 相似度度量:可衡量两个投资组合的相似程度

矩阵乘法的数学定义

矩阵 \(\mathbf{A}\)\(m \times n\))与 \(\mathbf{B}\)\(n \times p\))的乘积 \(\mathbf{C}\)\(m \times p\)):

\[ \large{c_{ij} = \sum_{k=1}^{n} a_{ik} b_{kj}} \]

重要性质

  • 不满足交换律\(\mathbf{AB} \neq \mathbf{BA}\)
  • 满足结合律\((\mathbf{AB})\mathbf{C} = \mathbf{A}(\mathbf{BC})\)
  • 维度要求\(\mathbf{A}\) 的列数必须等于 \(\mathbf{B}\) 的行数

矩阵乘法的三种实现方法

Listing 4: NumPy矩阵乘法的多种方法
展开实现代码
import numpy as np

A = np.array([[1, 2, 3], [4, 5, 6]])   # 2×3矩阵
B = np.array([[7, 8], [9, 10], [11, 12]])  # 3×2矩阵

# 方法1: @运算符(推荐,Python 3.5+)
C1 = A @ B
print('方法1 - @运算符:')
print(C1)

# 方法2: np.matmul()函数
C2 = np.matmul(A, B)
print('\n方法2 - matmul函数:')
print(C2)

# 方法3: np.dot()函数
C3 = np.dot(A, B)
print('\n方法3 - dot函数:')
print(C3)

print(f'\n结果一致: {np.array_equal(C1, C2) and np.array_equal(C2, C3)}')
方法1 - @运算符:
[[ 58  64]
 [139 154]]

方法2 - matmul函数:
[[ 58  64]
 [139 154]]

方法3 - dot函数:
[[ 58  64]
 [139 154]]

结果一致: True

金融应用:多期投资组合收益

Listing 5: 矩阵运算计算多期投资组合收益
import numpy as np

# 3只股票在4个交易日的收益率矩阵(每行一只股票,每列一个交易日)
returns = np.array([
    [0.01, 0.02, -0.01, 0.03],   # 股票A
    [0.02, 0.01, 0.03, -0.01],   # 股票B
    [-0.01, 0.03, 0.02, 0.04]    # 股票C
])

# 投资组合权重:A 30%、B 50%、C 20%
weights = np.array([0.3, 0.5, 0.2])

# 矩阵乘法:权重(1×3) × 收益率(3×4) = 组合收益(1×4)
portfolio_returns = weights @ returns
print(f'投资组合每日收益率: {portfolio_returns}')

# 累计收益率
cumulative_return = np.prod(1 + portfolio_returns) - 1
print(f'期间累计收益率: {cumulative_return:.4%}')
投资组合每日收益率: [0.011 0.017 0.016 0.012]
期间累计收益率: 5.7174%

协方差矩阵:金融风险管理的核心

对于随机向量 \(\mathbf{X}\),协方差矩阵 \(\mathbf{\Sigma}\) 的元素为:

\[ \large{\Sigma_{ij} = \text{Cov}(X_i, X_j) = E[(X_i - \mu_i)(X_j - \mu_j)]} \]

三大性质

  • 对称性\(\Sigma_{ij} = \Sigma_{ji}\)
  • 半正定性\(\mathbf{a}^T\mathbf{\Sigma}\mathbf{a} \geq 0\)
  • 对角线元素\(\Sigma_{ii} = \text{Var}(X_i)\)

计算协方差矩阵与相关系数矩阵

Listing 6: 计算协方差矩阵与相关系数矩阵
展开实现代码
import numpy as np

np.random.seed(42)
returns = np.random.randn(100, 3) * 0.02  # 100天×3只股票的随机收益率

# 协方差矩阵
cov_matrix = np.cov(returns, rowvar=False)
print('协方差矩阵:')
print(cov_matrix)

# 相关系数矩阵
corr_matrix = np.corrcoef(returns, rowvar=False)
print('\n相关系数矩阵:')
print(corr_matrix)
协方差矩阵:
[[ 2.72117409e-04 -1.57105634e-05 -4.43202407e-05]
 [-1.57105634e-05  3.83454758e-04 -5.39437601e-05]
 [-4.43202407e-05 -5.39437601e-05  4.95427395e-04]]

相关系数矩阵:
[[ 1.         -0.04863585 -0.12070741]
 [-0.04863585  1.         -0.12376394]
 [-0.12070741 -0.12376394  1.        ]]

从协方差矩阵推导相关系数矩阵

\[ \large{\text{Corr}(X, Y) = \frac{\text{Cov}(X, Y)}{\sigma_X \cdot \sigma_Y}} \]

Listing 7: 从协方差矩阵推导相关系数矩阵
展开实现代码
import numpy as np

np.random.seed(42)
returns = np.random.randn(100, 3) * 0.02
cov_matrix = np.cov(returns, rowvar=False)
corr_matrix = np.corrcoef(returns, rowvar=False)

# 标准差向量
std_devs = np.sqrt(np.diag(cov_matrix))
# 外积构造分母矩阵
corr_from_cov = cov_matrix / np.outer(std_devs, std_devs)
print('从协方差计算的相关系数矩阵:')
print(corr_from_cov)

print(f'\n两种方法一致: {np.allclose(corr_matrix, corr_from_cov)}')
从协方差计算的相关系数矩阵:
[[ 1.         -0.04863585 -0.12070741]
 [-0.04863585  1.         -0.12376394]
 [-0.12070741 -0.12376394  1.        ]]

两种方法一致: True

投资组合方差:马科维茨核心公式

\[ \large{\sigma_p^2 = \mathbf{w}^T \mathbf{\Sigma} \mathbf{w} = \sum_{i=1}^{n}\sum_{j=1}^{n} w_i w_j \sigma_{ij}} \]

  • \(\mathbf{w}\):资产权重向量
  • \(\mathbf{\Sigma}\):协方差矩阵
  • \(\sigma_p^2\):投资组合方差

矩阵运算计算投资组合方差

Listing 8: 使用矩阵运算计算投资组合方差
import numpy as np

# 3只股票的协方差矩阵
cov_matrix = np.array([
    [0.0100, 0.0018, 0.0011],
    [0.0018, 0.0081, 0.0009],
    [0.0011, 0.0009, 0.0064]
])

weights = np.array([0.3, 0.5, 0.2])  # A 30%, B 50%, C 20%

# 矩阵运算:wΣw'
portfolio_var = weights @ cov_matrix @ weights.T
portfolio_std = np.sqrt(portfolio_var)

print(f'投资组合方差: {portfolio_var:.6f}')
print(f'投资组合标准差(波动率): {portfolio_std:.4%}')
投资组合方差: 0.004033
投资组合标准差(波动率): 6.3506%

分散化效应:何时严格降低风险

在权重非负且和为 1 时,\(\sigma_p \leq \sum_i w_i\sigma_i\)。只有至少一对正权重、非零风险资产的相关系数小于 1 时才严格小于;所有正权重资产完全同向相关时取等号。

Listing 9: 分散化效应验证
展开实现代码
import numpy as np

cov_matrix = np.array([
    [0.0100, 0.0018, 0.0011],
    [0.0018, 0.0081, 0.0009],
    [0.0011, 0.0009, 0.0064]
])
weights = np.array([0.3, 0.5, 0.2])

portfolio_std = np.sqrt(weights @ cov_matrix @ weights.T)
individual_stds = np.sqrt(np.diag(cov_matrix))
weighted_avg_std = np.sum(weights * individual_stds)

print(f'加权平均标准差: {weighted_avg_std:.4%}')
print(f'组合标准差:     {portfolio_std:.4%}')
print(f'风险降低:       {(weighted_avg_std - portfolio_std) / weighted_avg_std:.2%}')
# 体现了"不要把鸡蛋放在同一个篮子里"的原理
加权平均标准差: 9.1000%
组合标准差:     6.3506%
风险降低:       30.21%

可选扩展|线性系统、APT 与 PCA

以下内容供已学过矩阵秩、线性方程组和最小二乘的学习者选修,不纳入本章核心内容。先判断形状与秩,再选 solvelstsqpinv;条件数过高或缺少经济含义时,不作进一步解释。

扩展|线性方程组求解:\(\mathbf{Ax} = \mathbf{b}\)

金融中许多问题可转化为线性方程组:

  • 因子收益计算:从资产收益反推因子收益
  • 套利定价理论(APT):求解无风险组合权重
  • 状态估计:Kalman滤波中的状态更新

扩展|求解因子收益(APT应用)

Listing 10: 求解线性方程组在金融中的应用
展开实现代码
import numpy as np

# 因子载荷矩阵:3只资产对3个因子的敏感度
A = np.array([
    [1.2, 0.8, 0.5],  # 资产1
    [0.9, 1.1, 0.3],  # 资产2
    [0.7, 0.6, 0.9]   # 资产3
])

b = np.array([0.08, 0.06, 0.07])  # 资产超额收益率

# 求解因子收益:Ax = b
factor_returns = np.linalg.solve(A, b)
print('因子收益率:')
print(f'  因子1: {factor_returns[0]:.4%}')
print(f'  因子2: {factor_returns[1]:.4%}')
print(f'  因子3: {factor_returns[2]:.4%}')

# 验证
b_reconstructed = A @ factor_returns
print(f'\n验证通过: {np.allclose(b, b_reconstructed)}')
因子收益率:
  因子1: 4.7480%
  因子2: 0.5570%
  因子3: 3.7135%

验证通过: True

扩展|矩阵的秩与逆:核心概念

矩阵可逆的充要条件

  • \(\det(\mathbf{A}) \neq 0\)(行列式不为零)
  • \(\text{rank}(\mathbf{A}) = n\)(满秩)
  • \(\mathbf{Ax} = \mathbf{0}\) 只有零解

逆矩阵性质\(\mathbf{A} \times \mathbf{A}^{-1} = \mathbf{I}\)

扩展|矩阵的秩与逆运算

Listing 11: 矩阵的秩与逆运算
展开实现代码
import numpy as np

A = np.array([[4, 7], [2, 6]])
print('矩阵A:')
print(A)

# 行列式
det_A = np.linalg.det(A)
print(f'\n行列式: {det_A:.4f}')

# 秩
rank_A = np.linalg.matrix_rank(A)
print(f'秩: {rank_A}')

# 逆矩阵
A_inv = np.linalg.inv(A)
print('\n逆矩阵 A^(-1):')
print(A_inv)

# 验证 A × A^(-1) = I
identity = A @ A_inv
print(f'\n是否为单位矩阵: {np.allclose(identity, np.eye(2))}')
矩阵A:
[[4 7]
 [2 6]]

行列式: 10.0000
秩: 2

逆矩阵 A^(-1):
[[ 0.6 -0.7]
 [-0.2  0.4]]

是否为单位矩阵: True

扩展|利用逆矩阵求解方程组

Listing 12: 利用逆矩阵求解方程组
import numpy as np

A = np.array([[4, 7], [2, 6]])
A_inv = np.linalg.inv(A)

# 方程组 Ax = b,解为 x = A^(-1) × b
b = np.array([1, 2])
x = A_inv @ b
print(f'方程组Ax=b的解: {x}')
方程组Ax=b的解: [-0.8  0.6]

数值稳定性提示:接近奇异的矩阵(行列式接近0)会导致数值不稳定。在金融中,协方差矩阵接近奇异意味着存在高度相关的资产。

扩展|特征值与特征向量:定义

对于方阵 \(\mathbf{A}\),若存在非零向量 \(\mathbf{v}\) 和标量 \(\lambda\) 使得:

\[ \large{\mathbf{Av} = \lambda\mathbf{v}} \]

\(\lambda\)特征值\(\mathbf{v}\)特征向量

金融应用

  • 主成分分析(PCA):降维和因子提取
  • 协方差矩阵对角化:找到不相关的风险因子
  • 马尔可夫链:稳态分布计算

扩展|特征值分解与主成分分析(PCA)

Listing 13: 特征值分解在主成分分析中的应用
展开完整代码
import numpy as np

cov_matrix = np.array([
    [0.0100, 0.0018, 0.0011],
    [0.0018, 0.0081, 0.0009],
    [0.0011, 0.0009, 0.0064]
])

# eigh:对称矩阵的特征值分解(特征值升序排列)
eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)

print('特征值:')
for i, val in enumerate(eigenvalues):
    print(f'  λ{i+1} = {val:.6f}')

# 解释方差比例
explained_var_ratio = eigenvalues / eigenvalues.sum()
print(f'\n解释方差比例:')
for i, ratio in enumerate(explained_var_ratio):
    print(f'  PC{i+1}: {ratio:.2%}')

# 累计解释方差
cumulative_var = np.cumsum(explained_var_ratio)
print(f'\n累计解释方差:')
for i, cum_var in enumerate(cumulative_var):
    print(f'  前{i+1}个主成分: {cum_var:.2%}')
特征值:
  λ1 = 0.005973
  λ2 = 0.007051
  λ3 = 0.011476

解释方差比例:
  PC1: 24.38%
  PC2: 28.78%
  PC3: 46.84%

累计解释方差:
  前1个主成分: 24.38%
  前2个主成分: 53.16%
  前3个主成分: 100.00%

扩展|广义逆矩阵(伪逆)

对于非方阵或奇异矩阵,使用 Moore-Penrose 伪逆 求最小二乘解。

Listing 14: 伪逆在超定系统中的应用
展开实现代码
import numpy as np

# 超定系统:4个方程,2个未知数
A = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
b = np.array([1, 2, 3, 4])

# Moore-Penrose伪逆
A_pinv = np.linalg.pinv(A)

# 最小二乘解:最小化 ||Ax - b||²
x = A_pinv @ b
print(f'最小二乘解: {x}')

# 残差与均方误差
residual = b - (A @ x)
mse = np.mean(residual ** 2)
print(f'均方误差: {mse:.6f}')
最小二乘解: [5.55111512e-16 5.00000000e-01]
均方误差: 0.000000

本章小结|核心与扩展分开

操作 函数/运算符 用途
矩阵乘法 @ / np.matmul() 投资组合计算
协方差矩阵 np.cov() 风险度量
扩展:线性方程组 np.linalg.solve() 满秩方阵求解
扩展:逆矩阵 np.linalg.inv() 小型方阵概念演示
扩展:特征值分解 np.linalg.eigh() PCA探索性降维
扩展:伪逆 np.linalg.pinv() 秩与识别边界演示

随堂练习

  • 问题 1|需要准备哪些数据?:收益矩阵、资产权重与协方差矩阵。
  • 问题 2|需要完成哪些操作?:运行 lst-covariance-matrixlst-portfolio-variance,用矩阵乘法计算组合风险。
  • 问题 3|应得到哪些结果?:协方差矩阵、相关矩阵、权重和与组合方差。
  • 问题 4|怎样确认结果可靠?:以双重求和复算 w’Σw;维度错位、权重和不为1或矩阵非有限时先检查原因。
  • 问题 5|换一个情境,怎样继续应用?:把矩阵风险分析应用到另一权重方案。
  • 作答提示:请依次写清所用数据、分析过程、所得结果、核对方法和拓展思考。课程所需数据见前言中的下载入口;教学平台固定题按页面说明完成。

教师参考解答|答案与说明 1

  • 补充练习|协方差、相关与组合方差

教师参考解答|代码 1

展开代码(代码区可独立滚动)
import numpy as np  # 导入矩阵计算库
return_matrix=np.array([[0.01,0.02],[0.03,0.01],[-0.02,-0.01],[0.02,0.03]])  # 定义同一时间段的收益矩阵
covariance_matrix=np.cov(return_matrix,rowvar=False,ddof=1)  # 计算样本协方差
correlation_matrix=np.corrcoef(return_matrix,rowvar=False)  # 计算无量纲相关矩阵
weights=np.array([0.6,0.4])  # 定义与资产列顺序一致的权重
portfolio_variance=weights@covariance_matrix@weights  # 计算矩阵形式组合方差
double_sum=sum(weights[i]*weights[j]*covariance_matrix[i,j] for i in range(2) for j in range(2))  # 用双重求和独立复算
assert np.isclose(weights.sum(),1.0)  # 核对权重和
assert np.isclose(portfolio_variance,double_sum)  # 核对两种计算一致
print(covariance_matrix,correlation_matrix,portfolio_variance)  # 输出核心达成依据

教师参考解答|答案与说明 2

  • 解释与拓展应用答案:矩阵统一表达多资产风险,但相关只描述线性同动;拓展应用时保持资产顺序一致,重新核对权重和,并用双重求和验证 \(w'\Sigma w\)

  • 所用数据与字段:权重 w 与协方差矩阵 Σ 的资产顺序一致

  • 参考代码或推导(平台保护块之外):

教师参考解答|代码 2

展开代码(代码区可独立滚动)
import numpy as np  # 导入矩阵库
w=np.array([0.6,0.4])  # 定义权重
sigma=np.array([[0.04,0.01],[0.01,0.09]])  # 定义协方差
print(round(w@sigma@w,6))  # 计算组合方差

教师参考解答|答案与说明 3

  • 参考结果:0.0336;Σ 对称且权重和为1
  • 边界 / 局限:协方差不是相关系数
  • 常见错误:逐元素乘法;权重未归一